package com.dhcc.bpm.modules.scf.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dhcc.bpm.common.segmentId.LocalCacheIdGenerator;
import com.dhcc.bpm.common.utils.StringUtils;
import com.dhcc.bpm.modules.scf.dto.ScfFileInfoDTO;
import com.dhcc.bpm.modules.scf.entity.ScfFileInfo;
import com.dhcc.bpm.modules.scf.mapper.ScfFileInfoMapper;
import com.dhcc.bpm.modules.scf.service.IScfFileInfoService;
import com.dhcc.bpm.modules.scf.util.OBSUtil;
import com.dhcc.bpm.modules.scf.vo.ScfFileInfoVO.ScfGetFileListVO;
import org.springblade.core.tool.api.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Service
public class ScfFileInfoServiceImpl extends ServiceImpl<ScfFileInfoMapper, ScfFileInfo> implements IScfFileInfoService {
    private final LocalCacheIdGenerator localCacheIdGenerator;
    private final OBSUtil obsUtil;

    @Autowired
    public ScfFileInfoServiceImpl(LocalCacheIdGenerator localCacheIdGenerator, OBSUtil obsUtil) {
        this.localCacheIdGenerator = localCacheIdGenerator;
        this.obsUtil = obsUtil;
    }

    /**
     * 自定义分页列表查询
     *
     * @param page
     * @param scfFileInfo
     * @return
     */
    @Override
    public IPage<ScfGetFileListVO> selectScfFileInfoPage(IPage<ScfGetFileListVO> page, ScfFileInfoDTO scfFileInfo) {
        return page.setRecords(baseMapper.selectScfFileInfoPage(page, scfFileInfo));
    }

    /**
     * 查询所有文件名称
     *
     * @return
     */
    @Override
    public List<String> selectScfFileInfoFileName() {
        return baseMapper.selectScfFileInfoFileName();
    }


    /**
     * 上传成功后将文件信息存储到文件存储信息表中
     *
     * @param scfFileInfo
     * @return
     */
    @Override
    public boolean insertScfFileInfo(ScfFileInfo scfFileInfo) {
        int rowCount = baseMapper.insertScfFileInfo(scfFileInfo);
        return rowCount > 0;
    }


    /**
     * 根据文件编号删除文件表中文件包记录
     *
     * @param fileNum
     * @return
     */
    @Override
    public boolean deleteByFileNum(String fileNum) {
        int rowCount = baseMapper.deleteByFileNum(fileNum);
        return rowCount > 0;
    }

    /**
     * 根据文件编号查询表中文件名称及路径
     *
     * @param fileNum
     * @return
     */
    @Override
    public ScfFileInfo getByFileInfo(String fileNum) {
        return baseMapper.getByFileInfo(fileNum);
    }


    /**
     * 更新下载次数
     *
     * @param fileNum
     */
    @Override
    public void updataDownloadCount(String fileNum) {
        baseMapper.updataDownloadCount(fileNum);
    }

    /**
     * 上传文件
     *
     * @param subNum
     * @param userId
     * @param file
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Boolean> uploadFile(String subNum, String userId, MultipartFile file) {
        // 判断主体编号和文件名是否为空
        if (StringUtils.isEmpty(subNum) || file.isEmpty()) {
            return R.fail("主体编号和文件不能为空");
        }
        try {
            // 获取文件名.拓展名 如：test.zip
            String fileName = file.getOriginalFilename();
            if (fileName == null) {
                throw new NullPointerException("文件名不能为空!");
            }
            // 获取拓展名
            String fileExtension = "";
            String startfileName = "";
            int dotIndex = fileName.lastIndexOf(".");
            if (dotIndex != -1) {
                fileExtension = fileName.substring(dotIndex + 1).toLowerCase();
                startfileName = fileName.substring(0, dotIndex);
            }

            // 判断是否为压缩文件：Zip,7z，rar,tar.gz。
            if (!fileExtension.equals("zip") && !fileExtension.equals("7z") && !fileExtension.equals("rar") && !fileExtension.equals("tar.gz")) {
                return R.fail("只能上传压缩文件，请重新上传！");
            }

            // 生成保存路径
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            String dateStr = sdf.format(new Date());
            // 生成文件编号
            String fileNumber = String.format("%06d", (int) (Math.random() * 1000000));
            // 生成新的文件名
            String fileNames = startfileName + dateStr + fileNumber + "." + fileExtension;
            // 判断数据库表中是否上传过同名文件
            // 查询所有记录的文件名
            List<String> list = selectScfFileInfoFileName();

            // 遍历对比文件名
            boolean fileExists = list.stream().anyMatch(fileNames::equals);

            // 检查文件是否已存在的逻辑
            if (fileExists) {
                return R.fail("文件已存在，不允许重复上传");
            }
            // 上传文件至OBS
            HashMap<String, String> stringObjectHashMap = obsUtil.uploadSegmentedFile(file, fileNames);
            // 正式objectKey
            String objectKey = subNum + "/" + dateStr + "/" + fileNames;
            // 封装实体类插入文件信息到数据库表中
            ScfFileInfo fileInfo = new ScfFileInfo();
            // 生成时间
            SimpleDateFormat timeFormat = new SimpleDateFormat("HHmmss");
            String formTime = timeFormat.format(new Date());
            // 生成ROW_ID
            String rowId = "WJ" + localCacheIdGenerator.nextId() + formTime;
            fileInfo.setRowId(rowId);
            fileInfo.setSubNum(subNum);
            fileInfo.setFileNum(fileNumber);
            fileInfo.setFileName(fileName);
            // 设置上传文件时间格式
            SimpleDateFormat sdftime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String formattedDate = sdftime.format(new Date());
            // 设置上传时间
            fileInfo.setGetDate(formattedDate);
            // 设置objectkey
            fileInfo.setPath(objectKey);
            // 设置上传用户id
            fileInfo.setOperatorId(userId);
            // 设置初始化下载次数
            fileInfo.setDownloadCount(0);

            boolean insertResult = insertScfFileInfo(fileInfo);
            if (!insertResult) {
                throw new RuntimeException("文件上传成功，但文件信息插入数据库失败！");
            }
            // 处理成功后，返回成功响应--文件信息记录插入数据库成功后才会将文件转移至正式目录中
            obsUtil.copyFile(objectKey, stringObjectHashMap.get("objectKey"));
            return R.success("上传成功！");
        } catch (Exception e) {
            return R.fail("上传失败！");
        }
    }

    /**
     * 删除一条文件记录，同步删除obs中存储的文件
     *
     * @param fileNum
     * @return
     */
    @Override
    public R<Boolean> deleteByFileNumS(String fileNum) {
        // 获取文件存储路径
        ScfFileInfo byFileInfo = getByFileInfo(fileNum);
        String objectKey = byFileInfo.getPath();

        // 删除obs上的文件
        Boolean deleteFile = obsUtil.deleteFile(objectKey);
        // 删除数据库表记录
        boolean deleteResult = deleteByFileNum(fileNum);
        if (Boolean.FALSE.equals(deleteFile) && Boolean.FALSE.equals(deleteResult)) {
            return R.fail("处理失败！");
        }
        if (Boolean.TRUE.equals(deleteFile) && Boolean.TRUE.equals(deleteResult)) {
            // 处理成功后，返回成功响应
            return R.success("处理成功！");
        } else {
            return R.fail("文件删除失败！");
        }
    }

    /**
     * @return 提供一个系统录入模板下载的接口
     * @throws IOException
     */
    @Override
    public String getTemplateUrl() throws IOException {
        String objectKey = "Template/绿链模板.xlsx";
        String downloadUrl = obsUtil.getDownloadUrl(objectKey);
        // 返回下载url
        return downloadUrl;
    }

    /**
     * 下载文件--暂时弃用，用url下载方式代替
     *
     * @param fileNum
     * @return
     * @throws IOException
     */
    @Override
    public ResponseEntity<byte[]> downloadFile(String fileNum) throws IOException {
        // 根据文件编号查询文件信息，获取文件路径和其他信息
        ScfFileInfo byFileInfo = getByFileInfo(fileNum);
        String objectKey = byFileInfo.getPath();
        String fileName = byFileInfo.getFileName();
        String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
        if (objectKey == null) {
            // 文件不存在，返回错误信息
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body(null);
        }
        // 文件存在，增加下载次数
        updataDownloadCount(fileNum);

        // 调用obs下载方法
        byte[] bytes = obsUtil.downloadFileAsBytes(objectKey);

        if (bytes.length == 0) {
            // 文件不存在，返回错误信息
            return ResponseEntity.status(HttpStatus.NOT_FOUND)
                    .body(null);
        }

        // 设置 HTTP 头信息，告诉浏览器如何处理下载文件
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"");

        // 创建 ResponseEntity 对象并返回文件资源
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(bytes.length)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(bytes);
    }

    /**
     * 获取下载url返回至前端
     * @param fileNum
     * @return
     */
    @Override
    public String getUrl(String fileNum) {
        // 根据文件编号查询文件信息，获取文件路径
        ScfFileInfo byFileInfo = getByFileInfo(fileNum);
        String objectKey = byFileInfo.getPath();
        String downloadUrl = obsUtil.getDownloadUrl(objectKey);
        // 文件存在，增加下载次数
        updataDownloadCount(fileNum);
        // 返回下载url
        return downloadUrl;
    }
}
